package com.infinova.datax.common.http;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson2.JSONObject;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URL;

import static com.alibaba.fastjson2.JSONWriter.Feature.PrettyFormat;

/**
 * @author bigbird-0101
 */
public class OkHttp3Client implements HttpClient {
    private final static Logger LOGGER =LoggerFactory.getLogger("com.infinova.datax.common.http.OkHttp3Client");
    private final OkHttpClient client;

    public OkHttp3Client() {
        this.client=new OkHttpClient();
    }

    public OkHttp3Client(OkHttpClient client) {
        this.client = client;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T handle(HttpRequest httpRequest, Type responseType) {
        if(LOGGER.isInfoEnabled()){
            LOGGER.info("request {}",JSONObject.toJSONString(httpRequest, PrettyFormat));
        }
        String requestUrl = httpRequest.getUrl();
        Assert.notBlank(requestUrl,"http url 为空");
        HttpUrl httpUrl = HttpUrl.parse(requestUrl);
        Assert.notNull(httpUrl,"http url 可能解析失败 srcUrl[{}]", requestUrl);
        HttpUrl.Builder httpUrlBuilder = httpUrl.newBuilder();
        JSONObject query = httpRequest.getQuery();
        if(CollUtil.isNotEmpty(query)){
            query.forEach((k,v)->{
                String headerValue = Convert.convert(String.class, v);
                httpUrlBuilder.addQueryParameter(k,headerValue);
            });
        }
        URL url = httpUrlBuilder.build().url();
        Assert.notNull(httpRequest.getMethod(),"http 请求方式为空");
        Request.Builder builder = new Request.Builder().url(url);
        JSONObject header = httpRequest.getHeader();
        if(CollUtil.isNotEmpty(header)){
            Headers.Builder headerBuilder = new Headers.Builder();
            header.forEach((k,v)->{
                String headerValue = Convert.convert(String.class, v);
                headerBuilder.set(k,headerValue);
            });
            builder.headers(headerBuilder.build());
        }
        JSONObject body= httpRequest.getBody();
        if(CollUtil.isNotEmpty(body)){
            MediaType parse = MediaType.parse("application/json");
            RequestBody requestBody = RequestBody.create(body.toJSONString(), parse);
            builder.method(httpRequest.getMethod().name(),requestBody);
        }
        Request request = builder.build();
        try (Response response = client.newCall(request).execute()) {
            ResponseBody responseBody = response.body();
            if(LOGGER.isInfoEnabled()){
                LOGGER.info("request response {}",JSONObject.toJSONString(responseBody, PrettyFormat));
            }
            if(null==responseBody){
                return null;
            }
            String string = responseBody.string();
            if(LOGGER.isInfoEnabled()){
                LOGGER.info("request response {}",string);
            }
            if(responseType.getTypeName().equals(String.class.getTypeName())){
                return (T) string;
            }
            return JSONObject.parseObject(string,responseType);
        } catch (IOException e) {
            if(LOGGER.isErrorEnabled()){
                LOGGER.error("request response",e);
            }
            throw new RuntimeException(e);
        }
    }

    @Override
    public void destroy() {
        try {
            client.dispatcher().executorService().shutdown();
        }catch (Exception exception){
            if(LOGGER.isErrorEnabled()){
                LOGGER.error("destroy executorService",exception);
            }
        }

        try {
            client.connectionPool().evictAll();
        }catch (Exception exception){
            if(LOGGER.isErrorEnabled()){
                LOGGER.error("destroy connectionPool",exception);
            }
        }

        try {
            Cache cache = client.cache();
            if(null!=cache){
                cache.close();
            }
        } catch (Exception e) {
            if(LOGGER.isErrorEnabled()){
                LOGGER.error("destroy cache",e);
            }
        }
    }
}